package com.waterworld.watch.common.customview;

import android.Manifest;
import android.app.Dialog;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.waterworld.watch.R;

import java.util.Timer;


public class ChatAudioRecordButton extends RelativeLayout {
    private static final int STATE_NORMAL = 1;
    private static final int STATE_RECORDING = 2;
    private static final int STATE_CANCELING = 3;
    private static final int MAX_VOLUME = 7;
    private static final float MSG_MAX_TIME_SECONDS = 10f;
    private static final float MSG_MIN_TIME_SECONDS = 1.0f;
    private static final int DISTANCE_Y_CANCEL = 38;
    private static final int MSG_TIME_OUT = 0x109;
    private static final int MSG_AUDIO_PREPARED = 0x110;
    private static final int MSG_VOICE_CHANGED = 0x111;
    private static final int MSG_DIALOG_DIMISS = 0x112;
    private static final int MSG_DIALOG_SHOW = 0x113;
    private static final int MSG_DIALOG_TOO_SHORT = 0x114;
    private static final int MSG_DIALOG_CANCELING = 0x115;
    private static final int MSG_DIALOG_TOO_LONG = 0x116;
    public static final int LAYOUT_RESOURCES_BIG = R.layout.chat_record_button_layout_big;
    public static final int LAYOUT_RESOURCES_SMALL = R.layout.chat_record_button_layout_small;

    private RecorderManager recorderManager;
    private Context context;
    private int currentState = STATE_NORMAL;
    private boolean isRecording = false;
    private float time = 0;
    private boolean ready;
    private TextView tvBtn;

    private Dialog recordDialog = null;
    private ImageView icon;
    private ImageView voice;
    private TextView label;
    private Timer timer;
    private static int layoutResourcesId = LAYOUT_RESOURCES_BIG;

    private Handler handlerRecord = new Handler();

    private AudioManager mAudioManager;
    private AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener()
    {
        @Override
        public void onAudioFocusChange(int focusChange)
        {
            switch (focusChange)
            {
                //失去焦点时调用
                case AudioManager.AUDIOFOCUS_LOSS:
                    //暂时失去焦点时调用
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                    //暂时失去焦点，并可以继续播放（需要降低音量）时调用
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                    if (!ready)    //Recorder还没有开始录音
                    {
                        reset();
                    }
                    if (!isRecording || time < MSG_MIN_TIME_SECONDS)   //录音时间太短
                    {
                        showVoiceDialog(MSG_DIALOG_TOO_SHORT);
                        recorderManager.cancel();
                        mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1000);
                    }
                    else if (currentState == STATE_RECORDING)  //录音正常结束
                    {
                        showVoiceDialog(MSG_DIALOG_DIMISS);
                        recorderManager.release();
                        if (audioFinishRecorderListener != null)
                        {
                            audioFinishRecorderListener.onFinish(time, recorderManager.getFileName());
                        }
                    }
                    else  //录音取消和其他非正常情况
                    {
                        showVoiceDialog(MSG_DIALOG_DIMISS);
                        recorderManager.cancel();
                    }
                    reset();
                    break;
                //重新获得焦点时调用
                case AudioManager.AUDIOFOCUS_GAIN:
                    break;
            }
        }
    };

    public static void setLayoutResourcesId(int resourcesId) {
        layoutResourcesId = resourcesId;
    }

    public ChatAudioRecordButton(Context context) {
        this(context, null);
    }

    public ChatAudioRecordButton(Context context, AttributeSet attrs) {
        super(context, attrs);

        this.context = context;
        if(!isInEditMode())
        {
            mAudioManager = (AudioManager) this.context.getSystemService(Context.AUDIO_SERVICE);
        }

        LayoutInflater.from(context).inflate(layoutResourcesId, this, true);
        tvBtn = findViewById(R.id.tv_button);

        String dir = Environment.getExternalStorageDirectory().getPath()+"/Android/data/com.waterworld.watch/files"+"/Temp";

        recorderManager = RecorderManager.getInstance(dir);
        recorderManager.setOnAudioStateListener(new RecorderManager.AudioStateListener() {

            public void wellPrepared() {
                ready = true;
                mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);
            }

            public void startFailed() {
                audioFinishRecorderListener.onFail();
            }
        });

        setOnLongClickListener(new OnLongClickListener() {

            public boolean onLongClick(View v) {
                recorderManager.prepareAudio();
                mAudioManager.requestAudioFocus(mAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
                return false;
            }
        });
    }

    @Override
    protected void onDetachedFromWindow()
    {
        super.onDetachedFromWindow();
    }

    public interface AudioFinishRecorderListener {
        void onFinish(float seconds, String fileName);
        void onFail();
        void onNoPermission();
    }

    private AudioFinishRecorderListener audioFinishRecorderListener;

    public void setAudioFinishRecorderListener(AudioFinishRecorderListener listener) {
        audioFinishRecorderListener = listener;
    }

    public interface OnFocusChangeListener {
        void onFocusChange(boolean hasFocus);
    }

    private OnFocusChangeListener onFocusChangeListener;

    public void setOnFocusChangeListener(OnFocusChangeListener listener) {
        onFocusChangeListener = listener;
    }

    Handler.Callback myCallback = new Handler.Callback()
    {
        @Override
        public boolean handleMessage(Message msg)
        {
            switch (msg.what) {
                case MSG_AUDIO_PREPARED:
                    if(ready)
                    {
                        showVoiceDialog(MSG_DIALOG_SHOW);
                        isRecording = true;
                        Runnable runnable = new Runnable() {
                            public void run() {
                                if (isRecording) {
                                    time += 0.2f;
                                    if (time >= MSG_MAX_TIME_SECONDS) {
                                        recorderManager.release();
                                        mHandler.sendEmptyMessage(MSG_TIME_OUT);
                                        mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1000);
                                        if (audioFinishRecorderListener != null) {
                                            audioFinishRecorderListener.onFinish(time, recorderManager.getFileName());
                                        }
                                    }
                                    mHandler.sendEmptyMessage(MSG_VOICE_CHANGED);
                                    handlerRecord.postDelayed(this, 200);
                                }
                            }
                        };
                        handlerRecord.postDelayed(runnable,200);
                    }
                    break;
                case MSG_VOICE_CHANGED:
                    showVoiceDialog(MSG_VOICE_CHANGED);
                    break;

                case MSG_DIALOG_DIMISS:
                    showVoiceDialog(MSG_DIALOG_DIMISS);
                    break;

                case MSG_TIME_OUT:
                    showVoiceDialog(MSG_DIALOG_TOO_LONG);
                    reset();
                    break;
            }
            return true;
        }
    };

    private Handler mHandler = new Handler(myCallback);

    @Override
    public boolean onTouchEvent(@NonNull MotionEvent event)
    {
        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                if (isHaveRecordPermission()) {
                    onFocusChangeListener.onFocusChange(true);
                    changeState(STATE_RECORDING);
                } else {
                    audioFinishRecorderListener.onNoPermission();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (isRecording)
                {
                    if (isCanceling(event.getX(), event.getY()))
                    {
                        changeState(STATE_CANCELING);
                    }
                    else
                    {
                        changeState(STATE_RECORDING);
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                if (!ready)    //Recorder还没有开始录音
                {
                    reset();
                    return super.onTouchEvent(event);
                }
                if (!isRecording || time < MSG_MIN_TIME_SECONDS)   //录音时间太短
                {
                    showVoiceDialog(MSG_DIALOG_TOO_SHORT);
                    recorderManager.cancel();
                    mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1000);
                }
                else if (currentState == STATE_RECORDING)  //录音正常结束
                {
                    showVoiceDialog(MSG_DIALOG_DIMISS);
                    recorderManager.release();
                    if (audioFinishRecorderListener != null)
                    {
                        audioFinishRecorderListener.onFinish(time, recorderManager.getFileName());
                    }
                }
                else  //录音取消和其他非正常情况
                {
                    showVoiceDialog(MSG_DIALOG_DIMISS);
                    recorderManager.cancel();
                }
                reset();
                break;
            default:
                showVoiceDialog(MSG_DIALOG_DIMISS);
                recorderManager.cancel();
                reset();
                break;
        }
        return super.onTouchEvent(event);
    }

    private void reset() {
        isRecording = false;
        time = 0;
        if (timer != null)
        {
            timer.cancel();
        }
        ready = false;
        changeState(STATE_NORMAL);
        mAudioManager.abandonAudioFocus(mAudioFocusChangeListener);
    }

    private boolean isCanceling(float x, float y) {
        return x < 0 || x > getWidth() || y < -DISTANCE_Y_CANCEL || y > getHeight() + DISTANCE_Y_CANCEL;
    }

    private void changeState(int state) {
        if (currentState != state) {
            currentState = state;
            switch (state) {
                case STATE_NORMAL:
                    tvBtn.setText(R.string.press_and_talk);
                    break;

                case STATE_RECORDING:
                    tvBtn.setText(R.string.btn_release_to_send);
                    if (isRecording) {
                        showVoiceDialog(MSG_DIALOG_SHOW);
                    }
                    break;

                case STATE_CANCELING:
                    tvBtn.setText(R.string.btn_release_to_cancel);
                    showVoiceDialog(MSG_DIALOG_CANCELING);
                    break;
            }
        }
    }

    private void showVoiceDialog(int flag)
    {
        if (recordDialog == null)
        {
            recordDialog = new Dialog(context, R.style.audio_dialog);
            recordDialog.setContentView(R.layout.chat_hint_dialog);
            recordDialog.setCancelable(false);
            icon = recordDialog.findViewById(R.id.id_recorder_dialog_icon);
            voice = recordDialog.findViewById(R.id.id_recorder_dialog_voice);
            label = recordDialog.findViewById(R.id.id_recorder_dialog_label);
        }
        switch (flag)
        {
            //dismiss
            case MSG_DIALOG_DIMISS:
                recordDialog.dismiss();
                break;
            //show
            case MSG_DIALOG_SHOW:
                icon.setVisibility(View.VISIBLE);
                voice.setVisibility(View.VISIBLE);
                label.setVisibility(View.VISIBLE);
                icon.setImageResource(R.drawable.chat_recorder);
                label.setTextColor(context.getResources().getColor(R.color.white_1));
                label.setText(R.string.btn_up_and_cancel);
                recordDialog.show();
                break;
            //change volume
            case MSG_VOICE_CHANGED:
                if(isRecording)
                {
                    int level = recorderManager.getVoiceLevel(MAX_VOLUME);
                    int resId = context.getResources().getIdentifier("chat_voice_" + level, "drawable", context.getPackageName());
                    voice.setImageResource(resId);
                    recordDialog.show();
                }
                break;
            //too short
            case MSG_DIALOG_TOO_SHORT:
                icon.setVisibility(View.VISIBLE);
                voice.setVisibility(View.GONE);
                label.setVisibility(View.VISIBLE);

                icon.setImageResource(R.drawable.chat_voice_too_short);
                label.setTextColor(context.getResources().getColor(R.color.white_1));
                label.setText(R.string.record_too_short);
                recordDialog.show();
                break;
            //canceling
            case MSG_DIALOG_CANCELING:
                icon.setVisibility(View.VISIBLE);
                voice.setVisibility(View.GONE);
                label.setVisibility(View.VISIBLE);

                icon.setImageResource(R.drawable.chat_cancel);
                label.setTextColor(context.getResources().getColor(R.color.yellow_1));
                label.setText(R.string.btn_release_to_cancel);
                recordDialog.show();
                break;
            case MSG_DIALOG_TOO_LONG:
                icon.setVisibility(View.VISIBLE);
                voice.setVisibility(View.GONE);
                label.setVisibility(View.VISIBLE);

                icon.setImageResource(R.drawable.chat_voice_too_short);
                label.setTextColor(context.getResources().getColor(R.color.white_1));
                label.setText(R.string.record_too_long);
                recordDialog.show();
            default:
                break;
        }
    }

    private boolean isHaveRecordPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO)) {
                return false;
            }
        }
        return true;
    }
}
